如何在 DrRacket 中实现结构化编辑

#Innolight #Racket

结构化编辑

通过在 DrRacket 中安装 drracket-paredit 插件,可以帮助我们在操作 S 表达式(S-expression )时保持代码的结构性,从而避免在手动调整括号时引入问题。插件主要包含的功能如下:

Warning

在使用快捷键之前,必须先进入 Edit → Preferences → Editing,取消勾选「Enable keybindings in menus (overrides Emacs keybinds)」,否则所有 paredit 快捷键都不会生效。修改后需要重启 DrRacket。

快捷键介绍

drracket-paredit 包含的快捷键如下:

Movement:

Depth-Changing:

Slurpage & barfage

下面介绍一下各个快捷键的使用场景

Note

如果不了解快捷键的含义,可以参考这篇文章 DrRacket 键盘快捷键完全指南

移动(Movement)

这些快捷键让你能够快速地在代码中以 S 表达式为单位导航,而不是逐字符或逐词移动。

场景:跳转到下一个 S 表达式的末尾 示例:

(define (square x) (* x |x))
; 光标在 | 处,按 c:m:f 跳到 x 后面
(define (square x) (* x x|))

场景:跳到当前或上一个 S 表达式的开头 示例:

(define (square x) (* x x|))
; 光标在 | 处,按 c:m:b 跳到当前 x 的开头
(define (square x) (* x |x))

场景:进入当前 S 表达式的下一层 示例:

(define |(square x) (* x x))
; 光标在 | 处,按 c:m:d 进入子表达式
(define (|square x) (* x x))

场景:跳到下一个符号或原子(类似 forward-word) 示例:

(define |square x)
; 从 | 处按 m:right 跳到下一个原子的末尾
(define square| x)

场景:与 m:right 相反,跳到上一个符号或原子 示例:

(define square |x)
; 从 | 处按 m:left 跳到前一个原子
(define |square x)

深度变化(Depth-Changing)

这些快捷键用于修改表达式的结构(如合并、提取或包装)。

场景:移除当前表达式的外围括号,保持内部结构 示例:

(foo (bar |(+ 1 2)) baz)
; 光标在 | 处,按 m:s 移除 (bar ...) 的括号
(foo bar (+ 1 2) baz)

场景:用一对括号包裹当前表达式。 示例:

(foo |bar baz)
; 光标在 | 处,按 m:( 包裹 bar
(foo (bar) baz)

场景:移除外围括号,并删除光标前面的所有内容 示例:

(foo (bar |(+ 1 2)) baz)
; 光标在 | 处,按 m:up,删除光标前面的内容
(foo (+ 1 2) baz)

场景:移除外围括号,并删除光标位置及其后面的所有内容 示例:

(foo (|bar (+ 1 2)) baz)
; 光标在 | 处,按 m:down,删除光标及其后面的内容
(foo baz)

场景:将光标所在的 S 表达式提升,替换其父表达式 示例:

(* 10 (+ |(- 5 2) 3))
; 光标在 | 处,按 m:r,(- 5 2) 替换整个 (+ ...) 表达式
(* 10 (- 5 2))

场景:重新排列嵌套结构,将光标所在表达式与外层表达式互换位置 示例:

(let ([x 3]) (+ |(* 2 x) 1))
; 光标在 | 处,按 m:?,(* 2 x) 提升与 + 互换
(+ (let ([x 3]) (* 2 x)) 1)

吞吐与吐出(Slurpage & Barfage)

这些快捷键是操作括号范围的神器,可以让括号快速"吞"或"吐"邻近的表达式。

场景:将光标所在括号右边紧邻的表达式"吞"进括号内(扩大括号范围) 示例:

(foo (bar |baz) qux)
; 光标在括号内任意位置,按 c:right
(foo (bar baz qux))
; qux 被吞入括号内,右括号向右移动

场景:将光标所在括号左边紧邻的表达式"吞"进括号内(扩大括号范围) 示例:

(foo bar (|baz qux))
; 光标在括号内任意位置,按 c:m:left
(foo (bar baz qux))
; bar 被吞入括号内,左括号向左移动

场景:将光标所在括号内最右侧的表达式"吐"出括号外(缩小括号范围) 示例:

(foo (bar baz |qux))
; 光标在括号内任意位置,按 c:left
(foo (bar baz) qux)
; qux 被吐出括号外,右括号向左移动

场景:将光标所在括号内最左侧的表达式"吐"出括号外(缩小括号范围) 示例:

(foo (bar |baz qux))
; 光标在括号内任意位置,按 c:m:right
(foo bar (baz qux))
; bar 被吐出括号外,左括号向右移动

总结

这些快捷键配合使用,可以显著提升编辑代码的效率,同时保证代码的正确性,非常适合 Lisp 和 Racket 的开发者。